﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//一局麻将
public class MjRound : MonoBehaviour
{
    private static int s_Id;
    
    public eMjSitIndex m_FirstIndex = eMjSitIndex.None; //庄
    public int m_Id; //唯一标识
    public readonly List<MjCard> m_Cards = new List<MjCard>(); //剩余牌堆
    private int m_FaPaiIndex = 0;
    public int m_ChuIndex = (int)eMjSitIndex.None; //出牌人
    private HashSet<int> m_ActionChuIndexSet = new HashSet<int>();
    private int m_ChuId;
    public MjCard m_LastChuPai; //最后一次出的牌
    public readonly MjSitPlayer[] m_SitPlayers = new MjSitPlayer[4];

    private Coroutine m_ChuPaiCo; //自己的出牌倒计时
    private Coroutine m_NextAuto3ChuPaiCo;

    public MjRound()
    {
        m_Id = s_Id++;
        MjCard.CopyCards(m_Cards);
    }

    public void SetReady(eMjSitIndex sitIndex)
    {
        var sitPlayer = new MjSitPlayer(sitIndex);
        sitPlayer.m_IsReady = true;
        m_SitPlayers[(int)sitIndex] = sitPlayer;
    }

    public bool IsAllReady()
    {
        for (int i = 0; i < m_SitPlayers.Length; ++i)
        {
            var sitPlayer = m_SitPlayers[i];
            if (null == sitPlayer || !sitPlayer.m_IsReady)
                return false;
        }

        return true;
    }

    public void StartFaPai()
    {
        m_FirstIndex = eMjSitIndex.East; //庄家随机?

        MjCard.Shuffle(m_Cards);
        Debug.Log($"StartFaPai: {m_Cards.Count}");
        m_FaPaiIndex = 0;

        for (int i = 0; i < 3; ++i) //4张发三次
        {
            for (int j = 0; j < m_SitPlayers.Length; ++j)
            {
                var sitPlayer = m_SitPlayers[(int)(m_FirstIndex+j) % 4];
                //4张一发
                sitPlayer.StartFaPai(m_Cards[m_FaPaiIndex++]);
                sitPlayer.StartFaPai(m_Cards[m_FaPaiIndex++]);
                sitPlayer.StartFaPai(m_Cards[m_FaPaiIndex++]);
                sitPlayer.StartFaPai(m_Cards[m_FaPaiIndex++]);
            }
        }

        for (int i = 0; i < m_SitPlayers.Length; ++i) //先手拿2张, 其他人每人一张
        {
            var sitPlayer = m_SitPlayers[(int)(m_FirstIndex + i) % 4];
            //4张一发
            sitPlayer.StartFaPai(m_Cards[m_FaPaiIndex++]);
            if (0 == i)
            {
                sitPlayer.RoundFaPai(m_Cards[m_FaPaiIndex++]);

                //目前只是本地模拟, 只推一个人
                var mjActionData = new MjActionData();
                mjActionData.m_Action = (int)eMjAction.Start;
                mjActionData.m_CardIds = sitPlayer.GetHandCardIds();
                mjActionData.m_CardId = sitPlayer.LastFaCard.Id;
                mjActionData.m_Index = sitPlayer.SitIndex;

                MsgDispatch.Instance.Dispatch("Mj.ActionNoti", mjActionData);
            }
            sitPlayer.StartLiPai();
        }

        m_ChuId++;
        m_ChuIndex = (int)eMjSitIndex.East;
        m_ChuPaiCo = StartCoroutine(ChuPaiTimer(m_ChuId, 15));
    }

    IEnumerator ChuPaiTimer(int chuId, float sec = 1)
    {
        Debug.Log($"ChuPaiTimer: {chuId}");
        yield return new WaitForSeconds(sec); //出牌倒计时
        if (m_ChuId != chuId)
        {
            Debug.LogWarning($"ChuPaiTimer: {m_ChuId} != {chuId}");
            m_ChuPaiCo = null;
            yield break;
        }
        Debug.Log($"ChuPaiTimer-222");

        //自动出牌
        var sitPlayer = m_SitPlayers[(int)m_ChuIndex];
        var c = sitPlayer.LastFaCard;
        sitPlayer.RoundChuPai(c);

        //目前只是本地模拟, 只推一个人
        var mjActionData = new MjActionData();
        mjActionData.m_Action = (int)eMjAction.Chu;
        mjActionData.m_CardId = c.Id;
        mjActionData.m_Index = sitPlayer.SitIndex;

        m_ChuId++;
        m_ChuIndex = (m_ChuIndex + 1) % 4;
        MsgDispatch.Instance.Dispatch("Mj.ActionNoti", mjActionData);

        m_ChuPaiCo = null;
        m_NextAuto3ChuPaiCo = StartCoroutine(Next3AutoChuPai());
    }

    //时间到了没出牌, 出一张默认牌
    public void ChuPaiDefault()
    {
        if (m_ActionChuIndexSet.Count > 0)
        {
            Debug.LogWarning($"ChuPaiDefault: wait action chuPai");
            return;
        }
        if ((int) eMjSitIndex.East != m_ChuIndex)
        {
            Debug.LogWarning($"ChuPaiDefault: {m_ChuIndex} != {eMjSitIndex.East}");
            return;
        }
        Debug.Log($"ChuPaiDefault");

        if (null != m_ChuPaiCo) //停止自动出牌倒计时
        {
            StopCoroutine(m_ChuPaiCo);
            m_ChuPaiCo = null;
        }

        var sitPlayer = m_SitPlayers[(int)eMjSitIndex.East];
        var c = sitPlayer.LastFaCard;
        sitPlayer.RoundChuPai(c);

        //目前只是本地模拟, 只推一个人
        var mjActionData = new MjActionData();
        mjActionData.m_Action = (int)eMjAction.Chu;
        mjActionData.m_CardId = c.Id;
        mjActionData.m_Index = sitPlayer.SitIndex;

        MsgDispatch.Instance.Dispatch("Mj.ActionNoti", mjActionData);

        m_ChuId++;
        m_ChuIndex = (m_ChuIndex + 1) % 4;
        m_NextAuto3ChuPaiCo = StartCoroutine(Next3AutoChuPai());
    }

    public void ChuPai(int cardId)
    {
        if (m_ActionChuIndexSet.Count > 0)
        {
            Debug.LogWarning($"ChuPai: wait action chuPai");
            return;
        }
        if ((int)eMjSitIndex.East != m_ChuIndex)
        {
            Debug.LogWarning($"ChuPai: {m_ChuIndex} != {eMjSitIndex.East}");
            return;
        }
        var c = MjCard.GetCard(cardId);
        if (null == c) return;

        var sitPlayer = m_SitPlayers[(int)eMjSitIndex.East];
        if (!sitPlayer.RoundChuPai(c))
        {
            //没有这张牌
            return;
        }
        
        if (null != m_ChuPaiCo) //停止自动出牌倒计时
        {
            StopCoroutine(m_ChuPaiCo);
            m_ChuPaiCo = null;
        }
        
        //目前只是本地模拟, 只推一个人
        var mjActionData = new MjActionData();
        mjActionData.m_Action = (int)eMjAction.Chu;
        mjActionData.m_CardId = c.Id;
        mjActionData.m_Index = sitPlayer.SitIndex;

        MsgDispatch.Instance.Dispatch("Mj.ActionNoti", mjActionData);

        m_ChuId++;
        m_ChuIndex = (m_ChuIndex + 1) % 4;
        m_NextAuto3ChuPaiCo = StartCoroutine(Next3AutoChuPai());
    }

    public void Pass()
    {
        if (m_ActionChuIndexSet.Count > 0)
        {
            if (!m_ActionChuIndexSet.Contains((int)eMjSitIndex.East))
            {
                Debug.LogWarning($"Action: action not cointains:{eMjSitIndex.East}");
                return;
            }
        }
        m_ActionChuIndexSet.Clear();
        if (null != m_NextAuto3ChuPaiCo)
        {
            StopCoroutine(m_NextAuto3ChuPaiCo);
            m_NextAuto3ChuPaiCo = null;
        }

        var mjActionData = new MjActionData();
        mjActionData.m_Action = (int)eMjAction.Guo;
        mjActionData.m_Index = (int)eMjSitIndex.East; //谁过
        MsgDispatch.Instance.Dispatch("Mj.ActionNoti", mjActionData);

        m_ChuId++;
        m_ChuIndex++;
        m_NextAuto3ChuPaiCo = StartCoroutine(Next3AutoChuPai());
    }

    public void Peng()
    {
        if (m_ActionChuIndexSet.Count > 0)
        {
            if (!m_ActionChuIndexSet.Contains((int)eMjSitIndex.East))
            {
                Debug.LogWarning($"Action: action not cointains:{eMjSitIndex.East}");
                return;
            }
        }
        m_ActionChuIndexSet.Clear();
        if (null != m_NextAuto3ChuPaiCo)
        {
            StopCoroutine(m_NextAuto3ChuPaiCo);
            m_NextAuto3ChuPaiCo = null;
        }

        var lastSitPlayer = m_SitPlayers[m_ChuIndex];
        var lastChuCard = lastSitPlayer.GetLastChuCard();

        var sitPlayer2 = m_SitPlayers[0];
        sitPlayer2.Peng(lastChuCard, (eMjSitIndex)m_ChuIndex, out var c1, out var c2);

        var mjActionData = new MjActionData();
        mjActionData.m_Action = (int)eMjAction.Peng;
        mjActionData.m_LastChuIndex = m_ChuIndex; //被碰的人(即: 刚刚出牌的人)
        mjActionData.m_CardId = lastChuCard.Id; //被碰的牌

        mjActionData.m_Index = (int)eMjSitIndex.East; //发起碰的人
        mjActionData.m_CardIds = new int[] { c1.Id, c2.Id }; //发起碰的2张牌
        MsgDispatch.Instance.Dispatch("Mj.ActionNoti", mjActionData);

        m_ChuId++;
        m_ChuIndex = (int)eMjSitIndex.North;
        m_NextAuto3ChuPaiCo = StartCoroutine(Next3AutoChuPai());
    }

    public void Chi()
    {
        if (m_ActionChuIndexSet.Count > 0)
        {
            if (!m_ActionChuIndexSet.Contains((int)eMjSitIndex.East))
            {
                Debug.LogWarning($"Action: action not cointains:{eMjSitIndex.East}");
                return;
            }
        }
        m_ActionChuIndexSet.Clear();
        if (null != m_NextAuto3ChuPaiCo)
        {
            StopCoroutine(m_NextAuto3ChuPaiCo);
            m_NextAuto3ChuPaiCo = null;
        }

        var lastSitPlayer = m_SitPlayers[m_ChuIndex];
        var lastChuCard = lastSitPlayer.GetLastChuCard();

        var sitPlayer2 = m_SitPlayers[0];
        sitPlayer2.Peng(lastChuCard, (eMjSitIndex)m_ChuIndex, out var c1, out var c2);

        var mjActionData = new MjActionData();
        mjActionData.m_Action = (int)eMjAction.Peng;
        mjActionData.m_LastChuIndex = m_ChuIndex; //被碰的人(即: 刚刚出牌的人)
        mjActionData.m_CardId = lastChuCard.Id; //被碰的牌

        mjActionData.m_Index = (int)eMjSitIndex.East; //发起碰的人
        mjActionData.m_CardIds = new int[] { c1.Id, c2.Id }; //发起碰的2张牌
        MsgDispatch.Instance.Dispatch("Mj.ActionNoti", mjActionData);

        m_ChuId++;
        m_ChuIndex = (int)eMjSitIndex.North;
        m_NextAuto3ChuPaiCo = StartCoroutine(Next3AutoChuPai());
    }

    //其余3人自动摸牌, 出牌
    IEnumerator Next3AutoChuPai()
    {
        if (0 == m_ChuIndex)
        {
            Debug.LogWarning($"Next3AutoChuPai: error ChuIndex:0");
            yield break;
        }

        Debug.Log($"Next3AutoChuPai: {m_ChuIndex}");
        for (int i = m_ChuIndex; i < 4; ++i)
        {
            yield return new WaitForSeconds(0.5f);
            if (m_FaPaiIndex >= m_Cards.Count - 1)
            {
                //结束, 平局
                m_NextAuto3ChuPaiCo = null;
                yield break;
            }

            var sitPlayer = m_SitPlayers[m_ChuIndex];
            //发一张牌
            var c = m_Cards[m_FaPaiIndex++];
            sitPlayer.RoundFaPai(c);

            var mjActionData = new MjActionData();
            mjActionData.m_Action = (int)eMjAction.Fa;
            mjActionData.m_CardId = 0; //c.Id;
            mjActionData.m_Index = m_ChuIndex;
            MsgDispatch.Instance.Dispatch("Mj.ActionNoti", mjActionData);

            float chuTime = 1;// UnityEngine.Random.Range(3, 8);
            Debug.Log($"Next3AutoChuPai: chuTime:{chuTime}");
            yield return new WaitForSeconds(chuTime);

            //出一张牌
            sitPlayer.RoundChuPai(c);

            mjActionData = new MjActionData();
            mjActionData.m_Action = (int)eMjAction.Chu;
            mjActionData.m_CardId = c.Id;
            mjActionData.m_Index = m_ChuIndex;

            //我是否可以杠
            var nextActions = new List<int>();
            var mySitPlayer = m_SitPlayers[0];
            if (mySitPlayer.IsGang(c))
            {
                nextActions.Add((int)eMjAction.Gang);
                nextActions.Add((int)eMjAction.Peng);
            }
            else if (mySitPlayer.IsPeng(c))
            {
                nextActions.Add((int)eMjAction.Peng);
            }
            else
            {
                if (3 == m_ChuIndex) //上家出牌, 可以吃
                {
                    if (mySitPlayer.IsChi(c))
                    {
                        nextActions.Add((int)eMjAction.Chi);
                    }
                }
            }
            if (nextActions.Count > 0)
            {
                mjActionData.m_NextAction = nextActions.ToArray();
            }

            MsgDispatch.Instance.Dispatch("Mj.ActionNoti", mjActionData);

            if (nextActions.Count > 0) //等吃碰杠一定时间
            {
                m_ActionChuIndexSet.Add(0);
                yield return new WaitForSeconds(9999);
                //超过时间没出, 则进入下家发牌
                m_ActionChuIndexSet.Clear();
            }

            m_ChuId++;
            m_ChuIndex++;
        }

        yield return new WaitForSeconds(0.5f);
        m_ChuId++;
        m_ChuIndex = (int)eMjSitIndex.East;
        //又轮到庄家出牌
        {
            var sitPlayer = m_SitPlayers[m_ChuIndex];
            //发一张牌
            var c = m_Cards[m_FaPaiIndex++];
            sitPlayer.RoundFaPai(c);

            var mjActionData = new MjActionData();
            mjActionData.m_Action = (int)eMjAction.Fa;
            mjActionData.m_CardId = c.Id;
            mjActionData.m_Index = m_ChuIndex;
            MsgDispatch.Instance.Dispatch("Mj.ActionNoti", mjActionData);
        }

        m_NextAuto3ChuPaiCo = null;
        m_ChuPaiCo = StartCoroutine(ChuPaiTimer(m_ChuId, 30));
    }

}
